<?php

namespace SunAdmin\Task\jobs;

use SunAdmin\Model\TimerTaskLogModel;
use think\helper\Str;

/**
 * 日志清理任务
 * 负责清理过期的定时任务日志和系统日志文件
 */
class ClearLogJob extends JobBaseAbstract
{
    /**
     * 保留天数
     * @var int
     */
    protected $retentionDays = 7;

    /**
     * 设置保留天数
     * @param int $days
     * @return $this
     */
    public function setRetentionDays(int $days)
    {
        $this->retentionDays = $days;
        return $this;
    }

    /**
     * 执行日志清理任务
     */
    protected function main()
    {
        $this->log('开始执行日志清理任务，保留天数: ' . $this->retentionDays,'info');
        // 清理数据库中的定时任务日志
        $this->clearTaskLogs();
        // 清理系统日志文件
        $this->clearLogFiles();
    }

    /**
     * 清理数据库中的定时任务日志
     */
    protected function clearTaskLogs()
    {
        try {
            // 计算截止时间
            $cutoffTime = date('Y-m-d H:i:s', strtotime("-{$this->retentionDays} days"));

            $this->log('开始清理定时任务日志，截止时间: ' . $cutoffTime, 'info');
            
            // 获取要删除的记录数量
            $deleteCount = TimerTaskLogModel::where('add_time', '<', $cutoffTime)->count();
            
            if ($deleteCount > 0) {
                // 删除过期的日志记录
                $result = TimerTaskLogModel::where('add_time', '<', $cutoffTime)->delete();
                
                if ($result) {
                    $this->log("成功清理定时任务日志 {$deleteCount} 条记录", 'info');
                } else {
                    $this->log('定时任务日志清理失败', 'error');
                }
            } else {
                $this->log('没有需要清理的定时任务日志', 'info');
            }
            
        } catch (\Throwable $e) {
            $this->log('清理定时任务日志失败: ' . $e->getMessage().$e->getTraceAsString(), 'error');
        }
    }

    /**
     * 清理系统日志文件
     */
    protected function clearLogFiles()
    {
        try {
            $logPath = app()->getRootPath() . 'runtime/log';
            $this->log('开始清理系统日志文件，目录: ' . $logPath, 'info');
            
            if (!is_dir($logPath)) {
                $this->log('日志目录不存在: ' . $logPath, 'warning');
                return;
            }
            
            $deletedFiles = 0;
            $cutoffTimestamp = time() - ($this->retentionDays * 24 * 60 * 60);
            
            // 递归扫描日志目录
            $this->scanAndCleanLogDirectory($logPath, $cutoffTimestamp, $deletedFiles);
            
            if ($deletedFiles > 0) {
                $this->log("成功清理系统日志文件 {$deletedFiles} 个", 'info');
            } else {
                $this->log('没有需要清理的系统日志文件', 'info');
            }
            
        } catch (\Throwable $e) {
            $this->log('清理系统日志文件失败: ' . $e->getMessage().$e->getMessage(), 'error');
        }
    }

    /**
     * 递归扫描并清理日志目录
     * @param string $directory
     * @param int $cutoffTimestamp
     * @param int &$deletedFiles
     */
    protected function scanAndCleanLogDirectory($directory, $cutoffTimestamp, &$deletedFiles)
    {
        $iterator = new \DirectoryIterator($directory);
        
        foreach ($iterator as $fileInfo) {
            if ($fileInfo->isDot()) {
                continue;
            }
            
            $filePath = $fileInfo->getPathname();
            
            if ($fileInfo->isDir()) {
                // 递归处理子目录
                $this->scanAndCleanLogDirectory($filePath, $cutoffTimestamp, $deletedFiles);
                
                // 检查目录是否为空，如果为空则删除
                if ($this->isDirEmpty($filePath)) {
                    if (@rmdir($filePath)) {
                        $this->log('删除空目录: ' . $filePath, 'info');
                    }
                }
            } elseif ($fileInfo->isFile()) {
                // 检查文件是否为日志文件
                if ($this->isLogFile($fileInfo)) {
                    $fileTime = $fileInfo->getMTime();
                    
                    // 如果文件修改时间早于截止时间，则删除
                    if ($fileTime < $cutoffTimestamp) {
                        if (@unlink($filePath)) {
                            $deletedFiles++;
                            $this->log('删除过期日志文件: ' . $filePath, 'info');
                        } else {
                            $this->log('删除日志文件失败: ' . $filePath, 'warning');
                        }
                    }
                }
            }
        }
    }

    /**
     * 判断是否为日志文件
     * @param \DirectoryIterator $fileInfo
     * @return bool
     */
    protected function isLogFile($fileInfo)
    {
        $fileName = $fileInfo->getFilename();
        $extension = $fileInfo->getExtension();
        
        // 检查文件扩展名
        if (in_array(strtolower($extension), ['log', 'txt'])) {
            return true;
        }
        
        // 检查文件名模式（ThinkPHP 日志文件通常以日期命名）
        if (preg_match('/^\d{4}-\d{2}-\d{2}/', $fileName) || 
            preg_match('/^\d{8}/', $fileName) ||
            Str::contains($fileName, ['error', 'info', 'debug', 'warning'])) {
            return true;
        }
        
        return false;
    }

    /**
     * 检查目录是否为空
     * @param string $directory
     * @return bool
     */
    protected function isDirEmpty($directory)
    {
        $iterator = new \DirectoryIterator($directory);
        
        foreach ($iterator as $fileInfo) {
            if (!$fileInfo->isDot()) {
                return false;
            }
        }
        
        return true;
    }
} 